/***
 * author: Ivan Gonzalez
 * project: RoboCup2D 2012
 * version: 0.9
 */

/***
 * Probablemente en una version posterior cambie el tipo de objetos de retorno de los metodos de mensajes para
 * que puedan usarse a traves de pipes, esto mejora el rendimiento ya que en lugar de estar revisando 
 * constantemente si existe mensaje solamente se bloquea el metodo a traves de un reader, y se desbloquea hasta
 * que se recibe un mensaje
 */

import java.util.HashMap;
import java.util.Vector;
import java.util.concurrent.*;

public class Player {
	
	private int numberTypes;
	private Update comm;
	private boolean goalie;
	private World worldModel;
	private int readyToKick;

	public double xInit;
	public double yInit;
	
	public int recordAngle;
	public int recordDash;
	public boolean kickedBall;
	
	/***
	 * <syntax>
	 * 		player(String teamName, String host, boolean goalie)
	 * </syntax>
	 * <summary>
	 * 		Constructor del objeto player.  Se encarga de realizar la conexion y de inicializar las variables
	 * 		de numero de jugador y lado del equipo.  Finalmente inicializa el hilo de actualizacion de datos.
	 * </summary>
	 */
	
	public Player(String teamName, String host, boolean goalie) {
		this.comm = new Update(teamName,host,goalie);
		this.goalie = goalie;
		(new Thread(this.comm)).start();
        this.worldModel = new World();
        this.xInit = this.yInit = this.recordAngle = this.recordDash = 0;
        this.kickedBall = false;
        
	}
	
	/***
	 * <syntax>
	 * 		void disconnect()
	 * </syntax>
	 * <summary>
	 * 		Desconecta el proceso del servidor y termina el hilo de actualizacion de datos.
	 * </summary>
	 */
	
	public void disconnect() {
		this.comm.disconnect();
	}
	
	/***
	 * <syntax>
	 * 		int getNumber()
	 * </syntax>
	 * <summary>
	 * 		Regresa el numero de jugador asignado por el servidor.
	 * </summary>
	 */
	
	public int getNumber() {
		return this.comm.getNumber();
	}
	
	/***
	 * <syntax>
	 * 		String getSide()
	 * </syntax>
	 * <summary>
	 * 		Regresa el lado del jugador en formato String ("left" o "right") asignado por el servidor
	 * </summary>
	 */
	
	public String getSide() {
		return this.comm.getSide();
	}
	
	/***
	 * <syntax>
	 * 		String getServerParam(String parameter)
	 * </syntax>
	 * <summary>
	 * 		Regresa como String el valor del parametro del servidor asociado con el argumento parameter.
	 * 		Ejemplo:
	 * 			player p = new player("borregos","localhost",false);
	 * 			System.out.println(p.getServerParam("maxmoment"));
	 * 		Salida:
	 * 			180 //que corresponde a maxmoment
	 * </summary>
	 */
	
	public String getServerParam(String parameter) {
		return this.comm.getServerParam(parameter);
	}
	
	/***
	 * <syntax>
	 * 		String getPlayerParam(String parameter)
	 * </syntax>
	 * <summary>
	 * 		Regresa como String el valor del parametro del jugador asociado con el argumento parameter.
	 * 		Ejemplo:
	 * 			player p = new player("borregos","localhost",false);
	 * 			System.out.println(p.getPlayerParam("inertia_moment_delta_factor"));
	 * 		Salida:
	 * 			25 //que corresponde a inertia_moment_delta_factor
	 * </summary>
	 */
	
	public String getPlayerParam(String param) {
		return this.comm.getPlayerParam(param);
	}
	
	/***
	 * <syntax>
	 * 		boolean isGoalie()
	 * </syntax>
	 * <summary>
	 * 		Regresa true si el jugador fue inicializado como portero, false en caso contrario
	 * </summary>
	 */
	
	public boolean isGoalie() {
		return this.goalie;
	}
	
	/***
	 * <syntax>
	 * 		int getType()
	 * </syntax>
	 * <summary>
	 * 		Regresa el tipo de jugador (0 - [player_types - 1]) con el que esta siendo simulado el jugador.  El
	 * 		tipo por defecto es 0.
	 * </summary>
	 * <warning>
	 * 		Este metodo aun no esta completamente implementado por lo que siempre regresa 0
	 * </warning>
	 */
	
	public int getType() {
		return 0;
	}
	
	/***
	 * <syntax>
	 * 		int getNumberTypes()
	 * </syntax>
	 * <summary>
	 * 		Regresa la cantidad de tipos con el que puede ser simulado el jugador.  Otra forma de acceder a este
	 * 		dato es usando getPlayerParam:
	 * 			player p = new player("borregos","localhost",false);
	 * 			int player_types = Integer.parseInt(p.getPlayerParam("player_types"));
	 * </summary>
	 */
	
	public int getNumberTypes() {
		return this.numberTypes;
	}
	
	/***
	 * <syntax>
	 * 		String getTypeParam(String parameter, int type)
	 * </syntax>
	 * <summary>
	 * 		Regresa el parametro asociado con el argumento parameter del tipo de jugador indicado por el argumento
	 * 		type.
	 * </summary>
	 */
	
	public String getTypeParam(String param, int type) {
		return this.comm.getTypeParam(param, type);
	}
	
	/***
	 * <syntax>
	 * 		int getTime()
	 * </syntax>
	 * <summary>
	 * 		Regresa el tipo de jugador (0 - [player_types - 1]) con el que esta siendo simulado el jugador.  El
	 * 		tipo por defecto es 0.
	 * </summary>
	 */
	
	public int getTime() {
		return this.comm.getTime();
	}
	
	/***
	 * <syntax>
	 * 		String getPlayerStat(String stat)
	 * </syntax>
	 * <summary>
	 * 		Regresa el estado del jugador asociado con el argumento stat a partir del sensor body_sense que
	 * 		regresa el servidor.
	 * </summary>
	 */
	
	public String getPlayerStat(String stat) {
		return this.comm.getPlayerStat(stat);
	}
	
	/***
	 * <syntax>
	 * 		boolean hasNextPlayerMessage()
	 * </syntax>
	 * <summary>
	 * 		Regresa true si existe un mensaje en cola enviado por algun jugador, false en caso contrario.
	 * </summary>
	 */
	
	public boolean hasNextPlayerMessage() {
		return this.comm.playerMsgExist;
	}
	
	/***
	 * <syntax>
	 * 		message getNexPlayertMessage()
	 * </syntax>
	 * <summary>
	 * 		Regresa el primer mensaje en cola enviado por algun jugador en forma de objeto tipo message que 
	 * 		contiene los siguientes campos:
	 * 			int time; //ciclo en el que se recibio el mensaje
	 * 			int direction; //direccion desde la que se recibio el mensaje
	 * 			String text; //texto del mensaje
	 * 		Ejemplo:
	 * 			player p = new player("borregos","localhost",false);
	 * 			if (p.hasNextMessage()) {
	 * 				message msg = p.getNextMessage();
	 * 				String time = Integer.toString(msg.time);
	 * 				String direction = Integer.toString(msg.direction);
	 * 				System.out.println("Direction " + direction + " says: " + msg.text + " at time: " + time);
	 * 			} else {
	 * 				System.out.println("There is no message");
	 * 			} 
	 * </summary>
	 * <warning>
	 * 		En caso de acceder a este metodo cuando hasNextPlayerMessage() regresa false, este metodo enviara el 
	 * 		objeto message con un texto de error y direccion -1
	 * </warning>
	 */
	
	public Message getNextPlayerMessage() {
		return this.comm.getPlayerMsg(); //this.message;
	}
	
	/***
	 * <syntax>
	 * 		boolean hasNextRefereeMessage()
	 * </syntax>
	 * <summary>
	 * 		Regresa true si existe un mensaje en cola enviado por el referi, false en caso contrario.
	 * </summary>
	 */
	
	public boolean hasNextRefereeMessage() {
		return this.comm.nextRefereeMsg();
	}
	
	/***
	 * <syntax>
	 * 		message getNextRefereeMessage()
	 * </syntax>
	 * <summary>
	 * 		Regresa el primer mensaje en cola en forma de objeto tipo message enviado por el referi.
	 * </summary>
	 * <warning>
	 * 		En caso de acceder a este metodo cuando hasNextRefereeMessage() regresa false, este metodo enviara 
	 * 		el objeto message con un texto de error y direccion -1
	 * </warning>
	 */
	
	public Message getNextRefereeMessage() {
		return this.comm.getRefereeMsg();
	}
	
	/***
	 * <syntax>
	 * 		boolean hasNextCoachMessage()
	 * </syntax>
	 * <summary>
	 * 		Regresa true si existe un mensaje en cola enviado por el coach, false en caso contrario.  Este metodo
	 * 		funciona tanto si es un coach online u offline.
	 * </summary>
	 */
	
	public boolean hasNextCoachMessage() {
		return this.comm.nextCoachMsg();
	}
	
	/***
	 * <syntax>
	 * 		message getNextCoachMessage()
	 * </syntax>
	 * <summary>
	 * 		Regresa el primer mensaje en cola en forma de objeto tipo message enviado por el coach. Este metodo
	 * 		funciona tanto si es un coach online u offline.
	 * </summary>
	 * <warning>
	 * 		En caso de acceder a este metodo cuando hasNextCoachMessage() regresa false, este metodo enviara 
	 * 		el objeto message con un texto de error y direccion -1
	 * </warning>
	 */
	
	public Message getNextCoachMessage() {
		return this.comm.getCoachMsg();
	}
	
	/***
	 * <syntax>
	 * 		Vector<element> getTeamMates()
	 * </syntax>
	 * <summary>
	 * 		Regresa un vector con todos los companieros del equipo que estan a la vista del agente.  El vector esta
	 * 		formado por objetivos tipo element el cual incluye los siguientes metodos:
	 * 			int getNumber();  //regresa el numero de jugador
	 * 			boolean isGoalie(); //regresa true si es portero y false en caso contrario
	 * 			int type(); //regresa el tipo de informacion que contiene, es decir, la cantidad de datos que el
	 * 						//servidor envia en el sensor see
	 * 			double getValue(String value); //regresa el valor asociado con el argumento value
	 * 		Ejemplo:
	 * 			import java.util.*;  //siempre hay que importarla
	 * 			player p = new player("borregos","localhost",false);
	 * 			Vector<element> team = p.getTeamMates();
	 * 			for (int i = 0; i < team.size(); i++) {
	 * 				String number = Integer.parseInt(team.elementAt(i).getNumber());
	 * 				String distance = Double.parseDouble(team.elementAt(i).getValue("Distance"));
	 * 				System.out.println("Veo a " + number + " a distancia " + distance);
	 * 			}
	 * </summary>
	 * <warning>
	 * 		En caso de que el argumento value no haya sido enviado por el servidor, el metodo
	 * 		double getValue(String value) de los objetos tipo element regresara un objeto NULL.
	 * </warning>
	 */
	
	public Vector<Member> getTeamMates() {
		return this.comm.getTeamMates();
	}
	
	/***
	 * <syntax>
	 * 		Vector<element> getOpponents()
	 * </syntax>
	 * <summary>
	 * 		Regresa un vector con todos los jugadores del equipo contrario que estan a la vista del agente.  El 
	 * 		vector esta formado por objetivos tipo element.
	 * </summary>
	 * <warning>
	 * 		En caso de que el argumento value no haya sido enviado por el servidor, el metodo
	 * 		double getValue(String value) de los objetos tipo element regresara un objeto NULL.
	 * </warning>
	 */
	
	public Vector<Member> getOpponents() {
		return this.comm.getOpponents();
	}
	
	/***
	 * <syntax>
	 * 		Vector<element> getPlayers()
	 * </syntax>
	 * <summary>
	 * 		Regresa un vector con todos los jugadores de los que no pueda accederse al equipo al que pertenecen.  
	 * 		El  vector esta formado por objetivos tipo element.
	 * </summary>
	 * <warning>
	 * 		En caso de que el argumento value no haya sido enviado por el servidor, el metodo
	 * 		double getValue(String value) de los objetos tipo element regresara un objeto NULL.
	 * </warning>
	 */
	
	public Vector<Member> getPlayers() {
		return this.comm.getPlayers();
	}
	
	/***
	 * <status>
	 * 		Sujeto a revision de valor de returno, probablemente lo cambie a un objeto tipo element
	 * </status>
	 * <syntax>
	 * 		Vector<Double> getBall()
	 * </syntax>
	 * <summary>
	 * 		Regresa los datos recibidos del servidor a traves del sensor see.  Incluye los paramatros asociados
	 * 		con el objeto ball en el orden en que son recibidos (ver manual).
	 * 		Ejemplo:
	 * 			import java.utils.*;
	 * 			player p = new player("borregos","localhost",true);
	 * 			Vector<double> ball = p.getBall();
	 * 			int size = ball.size();
	 * 			switch (size) {
	 * 				case 0:
	 * 					System.out.println("No veo la pelota");
	 * 					break;
	 * 				case 1:
	 * 					String direction = Double.parseDouble(p.getBall().elementAt(0));
	 * 					System.out.println("Veo la pelota en la direccion " + direction);
	 * 					break;
	 * 				default:
	 * 					String distance = Double.parseDouble(p.getBall().elementAt(0));
	 * 					String direction = Double.parseDouble(p.getBall().elementAt(1));
	 * 					System.out.println("Veo la pelota en la direccion " + direction + " y a distancia " + distance);
	 * 					break;
	 * 			}
	 * </summary>
	 * <warning>
	 * 		En caso de no ver la pelota el tamanio del vector sera 0
	 * </warning>
	 */
	
	public Vector<Double> getBall() {
		return this.comm.getBall();
	}
	
	/***
	 * <status>
	 * 		Sujeto a revision de valor de returno, probablemente lo cambie a un objeto tipo element
	 * </status>
	 * <syntax>
	 * 		Vector<Double> getMyGoal()
	 * </syntax>
	 * <summary>
	 * 		Regresa los datos recibidos del servidor a traves del sensor see.  Incluye los paramatros asociados
	 * 		con el objeto goal en el orden en que son recibidos (ver manual).
	 * </summary>
	 * <warning>
	 * 		En caso de no ver la porteria el tamanio del vector sera 0
	 * </warning>
	 */
	
	public Vector<Double> getMyGoal() {
		return this.comm.getMyGoal();
	}
	
	public boolean isBallVisible()
	{
		return getBall().size() >= 2;
	}
	
	
	/***
	 * <status>
	 * 		Sujeto a revision de valor de returno, probablemente lo cambie a un objeto tipo element
	 * </status>
	 * <syntax>
	 * 		Vector<Double> getOpponentGoal()
	 * </syntax>
	 * <summary>
	 * 		Regresa los datos recibidos del servidor a traves del sensor see.  Incluye los paramatros asociados
	 * 		con el objeto goal del oponente en el orden en que son recibidos (ver manual).
	 * </summary>
	 * <warning>
	 * 		En caso de no ver la porteria del oponente el tamanio del vector sera 0
	 * </warning>
	 */
	
	public Vector<Double> getOpponentGoal() {
		return this.comm.getOpponentGoal();
	}
	
	/***
	 * <syntax>
	 * 		double getX()
	 * </syntax>
	 * <summary>
	 * 		Regresa la posicion absoluta en x aproximada del jugador
	 * </summary>
	 * <warning>
	 * 		Aun no estan validados todos los casos por lo que no va a estar siempre actualizado ya que realiza una
	 * 		triangulacion con dos flags que esten sobre la misma linea.
	 * </warning>
	 */
	
	public double getX() {
		return this.comm.getX();
	}
	
	/***
	 * <syntax>
	 * 		double getY()
	 * </syntax>
	 * <summary>
	 * 		Regresa la posicion absoluta en y aproximada del jugador
	 * </summary>
	 * <warning>
	 * 		Aun no estan validados todos los casos por lo que no va a estar siempre actualizado ya que realiza una
	 * 		triangulacion con dos flags que esten sobre la misma linea.
	 * </warning>
	 */
	
	public double getY() {
		return this.comm.getY();
	}
	
	public boolean getXYGoalie(Actions.Coordinate wrapper) {
		ConcurrentHashMap<String, ConcurrentHashMap<String,Double>> flags = getFlags("mp"); // pido las flags del centro
		
		if(flags != null){
			ConcurrentHashMap<String, Double> center = null;
			if(flags.containsKey("f p l c")) {
				 center = flags.get("f p l c");
			} else if(flags.containsKey("f p r c")) {
				center = flags.get("f p r c");
			}
			if(center != null) {
				double distance = center.containsKey("Distance") ? center.get("Distance") : -1;
				double direction = center.get("Direction");
				if(distance > -1 ) {
					double x = -36.5 - distance * Math.cos(Math.toRadians(direction));
					double y = -distance * Math.sin(Math.toRadians(direction));
					wrapper.x = x;
					wrapper.y = y;
					return true;
				}
			}
		}
		return false;
	}
	
	
    /***
     * <syntax>
     *              double getAngle()
     * </syntax>
     * <summary>
     *              Regresa la direccion absoluta en grados sexagesimales aproximada del jugador
     * </summary>
     * <warning>
     *              Aun no estan validados todos los casos por lo que no va a estar siempre actualizado ya que realiza una
     *              triangulacion con dos flags que esten sobre la misma linea.
     * </warning>
     */
    
    public double getAngle() {
            return this.comm.getAngle();
    }
	
    /***
	 * <status>
	 * 		Experimental
	 * </status>
	 * <syntax>
	 * 		HashMap<String,HashMap<String,Double>> getFlags(String flagType)
	 * </syntax>
	 * <summary>
	 * 		Regresa las banderas que el jugador ve en su rango de vision de acuerdo al argumento flagType que puede ser
	 * 			- "mg" : regresa las flags de la porteria del equipo
	 * 			- "og" : regresa las flags de la porteria del oponente
	 * 			- "mp" : regresa las flags del area grande de la porteria del equipo (por ejemplo "f p t 10")
	 * 			- "op" : regresa las flags del area grande de la porteria del oponente
	 * 			- "fb" : regresa las flags del limite fisico (por ejemplo "f r t 30")
	 * 			- "fc" : regresa las flags de las esquinas de la cancha
	 * 			- "ft" : regresa las flags de la media cancha ("f c", "f c t" y "f c b")
	 * 		Se regresa como un mapa que mapea el nombre de las flags a un mapa que mapea el parametro a su respectivo
	 * 		valor double. Ejemplo:
	 * 			HashMap<String,HashMap<String,Double>> flags = getFlags("ft"); // pido las flags del centro
	 * 			HashMap<String,Double> centerFlag = flags.get("f c"); // pido los datos de la flag "f c"
	 * 			Double direction = centerFlag.get("Direction"); // pido la direccion a la que veo la flag
	 * </summary>
	 * <warning>
	 * 		No estan validadas en la clase Player las peticiones a flgas que no existen o valores que no existen, por lo
	 * 		que debe preguntarse primero si existe o no la flag o el parametro requerido mediante el metodo containsKey() o
	 * 		de lo contrario lanzara una excepcion.  Ejemplo:
	 * 			HashMap<String,HashMap<String,Double>> flags = getFlags("ft"); // pido las flags del centro
	 * 			flags.
	 * 			
	 * </warning>
	 */

	public ConcurrentHashMap<String, ConcurrentHashMap<String,Double>> getFlags(String flagType) {
		return this.comm.getFlags(flagType);
	}
    
	/***
	 * <syntax>
	 * 		void catchBall(int direction)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (catch_ball direction) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de direccion fuera del rango de valores permitidos por
	 * 		el servidor.
	 * </warning>
	 */
	
	public void catchBall(int direction) {
		this.comm.catchBall(direction);
	}
	
	/***
	 * <syntax>
	 * 		void dash(int power)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (dash power) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de potencia fuera del rango de valores permitidos por
	 * 		el servidor.
	 * </warning>
	 */
	
	public void dash(int power) {
		this.comm.dash(power);
	}
	
	public void dash(int power, boolean isRecording) {
		if(isRecording)
			this.recordDash += power;
		this.dash(power);
	}
	
	/***
	 * <syntax>
	 * 		void kick(int power, int direction)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (kick power direction) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de potencia y direccion fuera del rango de valores 
	 * 		permitidos por el servidor.
	 * </warning>
	 */
	
	public void kick(int power, int direction) {
		this.comm.kick(power, direction);
	}
	
	/***
	 * <syntax>
	 * 		void move(double x, double y)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (move x y) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de posicion fuera del rango de valores permitidos por el 
	 * 		servidor.
	 * </warning>
	 */
	
	public void move(double x, double y) {
		this.xInit = x;
		this.yInit = y;
		this.comm.move(x, y);
	}
	
	public boolean isBallWithinKickingDistance()
	{
		return (isBallVisible() && getBall().elementAt(0) < .7);
	}	
	
	/***
	 * <syntax>
	 * 		void say(String message)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (say message) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de texto fuera del rango de valores permitidos por el 
	 * 		servidor.
	 * </warning>
	 */
	
	public void say(String message) {
		this.comm.say(message);
	}
	
	/***
	 * <syntax>
	 * 		void turn(int moment)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (turn moment) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de momentos fuera del rango de valores permitidos por el 
	 * 		servidor.
	 * </warning>
	 */
	
	public void turn(int moment) {
		this.comm.turn(moment);
	}
	
	public void turn(int moment, boolean isRecording) {
		if(isRecording)
			this.recordAngle += moment;
		this.turn(moment);
	}
	
	/***
	 * <syntax>
	 * 		void turnNeck(int angle)
	 * </syntax>
	 * <summary>
	 * 		Envia la peticion (turn_neck angle) al servidor.
	 * </summary>
	 * <warning>
	 * 		No estan validadas las entradas para valores de angulo fuera del rango de valores permitidos por el 
	 * 		servidor.
	 * </warning>
	 */
	
	public void turnNeck(int angle) {
		this.comm.turnNeck(angle);
	}
	
	private void CheckNextMessageForBallUpdates()
	{
		if(hasNextPlayerMessage())
		{
			Message m = getNextPlayerMessage();
			String[] parsedMessage = m.text.split(" "); //[0] = team, [1] = playerNum, [2] = actual message
			
			if(parsedMessage[0].equals("our"))
			{
				if(parsedMessage[2].contains("ballonme"))
				{
					worldModel.UpdatePlayerWithBallInfo( Short.parseShort( parsedMessage[1]), comm.getTime() );		
				}
				
			}
			else
			{
				//message is from other team
			}
			
		}
		else
		{
			//No new messages
		}
	}
	
	private void TellTeamPlayerHasBall()
	{
		say("ballonme");
	}
	
	private void UpdatePlayerWithBall()
	{
        double distanceToBall = Math.abs(worldModel.getBallDistance());
        if(  distanceToBall > 0 && distanceToBall < .7)
        {
        	TellTeamPlayerHasBall();
        }
        else
        {
        	CheckNextMessageForBallUpdates();
        }
	}
	
	public void updateWorldModel() 
	{
        Vector<Member> allies = this.comm.getTeamMates();
        Vector<Member> opponents = this.comm.getOpponents();
        Vector<Double> ball = this.comm.getBall();
        Vector<Double> myGoal = this.comm.getMyGoal();
        Vector<Double> opGoal = this.comm.getOpponentGoal();
        int timestamp = this.comm.getTime();
        
        double headAngleFromServer = 0;
        String head_angle_string = this.getPlayerStat("head_angle"); 
        if( head_angle_string != null)
        {
        	 headAngleFromServer = Double.parseDouble(head_angle_string);
        }
        double thisAngle = this.getAngle();
        double sumAngle = headAngleFromServer + thisAngle;
        double toDegrees = Math.toDegrees(sumAngle);
        //double headAngle = Math.toDegrees( +;
        double headAngle = sumAngle;
        

        UpdatePlayerWithBall();
        
        this.worldModel.updateAllies(allies,timestamp);
        this.worldModel.updateOpponents(opponents,timestamp );
        this.worldModel.updateBall(ball,timestamp);
        this.worldModel.updateMyGoal(this.getX(), this.getY(), headAngle, timestamp);
        this.worldModel.updateOpponentGoal(this.getX(), this.getY(), headAngle, timestamp);
	}

	public World getWorldModel() {
        return this.worldModel;
	}
	
	/*Test*/
	
	/*public static void main(String[] args) {
		player p = new player();
		System.out.println("Side: " + p.getSide());
		System.out.println("Player number: " + Integer.toString(p.getNumber()));
		p.disconnect();
	}*/
	
}
